Skip to content

ooooooo-q/cve-2022-32224-rails

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVE-2022-3222 ActiveRecord シリアライズ 動作確認

準備

bundle install

bin/rails db:migrate

モデル

bin/rails generate model User values:string
class User < ApplicationRecord
  serialize :values, Array
end

動作確認

配列をシリアライズして保存

 bundle exec rails c
Loading development environment (Rails 7.0.3.1)
irb(main):001:0> User.create(values: [16 * 16, "ffff"])
   (0.6ms)  SELECT sqlite_version(*)
  TRANSACTION (0.0ms)  begin transaction
  User Create (0.6ms)  INSERT INTO "users" ("values", "created_at", "updated_at") VALUES (?, ?, ?)  [["values", "---\n- 256\n- ffff\n"], ["created_at", "2022-07-17 07:46:18.593587"], ["updated_at", "2022-07-17 07:46:18.593587"]]
  TRANSACTION (0.4ms)  commit transaction
=>
#<User:0x0000000105ee1a78
 id: 3,
 values: [256, "ffff"],
 created_at: Sun, 17 Jul 2022 07:46:18.593587000 UTC +00:00,
 updated_at: Sun, 17 Jul 2022 07:46:18.593587000 UTC +00:00>

irb(main):002:0> User.last.values
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> [256, "ffff"]

class_name_or_coder として Array が指定されているため、文字列をそのままは渡せない

irb(main):001:0> User.create(values: 'aaa')
   (0.6ms)  SELECT sqlite_version(*)
.../activerecord-7.0.3.1/lib/active_record/coders/yaml_column.rb:36:in `assert_valid_value': can't serialize `values`: was supposed to be a Array, but was a String. -- "aaa" (ActiveRecord::SerializationTypeMismatch)

更新

irb(main):001:0> user = User.create!(values: ["aaa"])
   (0.6ms)  SELECT sqlite_version(*)
  TRANSACTION (0.0ms)  begin transaction
  User Create (0.4ms)  INSERT INTO "users" ("values", "created_at", "updated_at") VALUES (?, ?, ?)  [["values", "---\n- aaa\n"], ["created_at", "2022-07-17 11:50:58.515968"], ["updated_at", "2022-07-17 11:50:58.515968"]]
  TRANSACTION (0.4ms)  commit transaction
=>
#<User:0x00000001057b65a0
...
irb(main):002:0> user.update_column(:values, ["aaaa"])
  User Update (0.9ms)  UPDATE "users" SET "values" = ? WHERE "users"."id" = ?  [["values", "---\n- aaaa\n"], ["id", 8]]
=> true
irb(main):003:0> user.update_attribute(:values, ["fffff"])
  TRANSACTION (0.1ms)  begin transaction
  User Update (0.5ms)  UPDATE "users" SET "values" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["values", "---\n- fffff\n"], ["updated_at", "2022-07-17 11:52:01.795259"], ["id", 8]]
  TRANSACTION (1.0ms)  commit transaction
=> true
irb(main):004:0> user.update(values: ["aaaddd"])
  TRANSACTION (0.1ms)  begin transaction
  User Update (0.7ms)  UPDATE "users" SET "values" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["values", "---\n- aaaddd\n"], ["updated_at", "2022-07-17 11:52:25.306288"], ["id", 8]]
  TRANSACTION (1.1ms)  commit transaction
=> true

"'、改行を含む文字列のシリアライズ・デシリアライズ

irb(main):001:0> User.create(values: ["'", '"', {'"' => [{"aaa" => "aa\na\r"}]}])
   (0.6ms)  SELECT sqlite_version(*)
  TRANSACTION (0.0ms)  begin transaction
  User Create (0.7ms)  INSERT INTO "users" ("values", "created_at", "updated_at") VALUES (?, ?, ?)  [["values", "---\n- \"'\"\n- \"\\\"\"\n- \"\\\"\":\n  - aaa: \"aa\\na\\r\"\n"], ["created_at", "2022-07-17 07:50:43.091916"], ["updated_at", "2022-07-17 07:50:43.091916"]]
  TRANSACTION (0.4ms)  commit transaction
=>
#<User:0x000000010dfb3cc8
 id: 4,
 values: ["'", "\"", {"\""=>[{"aaa"=>"aa\na\r"}]}],
 created_at: Sun, 17 Jul 2022 07:50:43.091916000 UTC +00:00,
 updated_at: Sun, 17 Jul 2022 07:50:43.091916000 UTC +00:00>

irb(main):002:0> User.last.values
  User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> ["'", "\"", {"\""=>[{"aaa"=>"aa\na\r"}]}]

任意のクラスの復元

7.0.3では任意のクラスがシリアライズでの保存、読み込み時のデシリアライズができる

 bundle exec rails c
Loading development environment (Rails 7.0.3)
irb(main):001:0> gemspec = Gem::Specification.new("test")
=>
Gem::Specification.new do |s|
...
irb(main):002:0>
irb(main):003:0> user = User.create!(values: [gemspec])
   (0.5ms)  SELECT sqlite_version(*)
  TRANSACTION (0.1ms)  begin transaction
  User Create (0.4ms)  INSERT INTO "users" ("values", "created_at", "updated_at") VALUES (?, ?, ?)  [["values", "---\n- !ruby/object:Gem::Specification\n  name: test\n  version:\n  platform: ruby\n  authors: []\n  autorequire:\n  bindir: bin\n  cert_chain: []\n  date: 2022-07-17 00:00:00.000000000 Z\n  dependencies: []\n  description:\n  email:\n  executables: []\n  extensions: []\n  extra_rdoc_files: []\n  files: []\n  homepage:\n  licenses: []\n  metadata: {}\n  post_install_message:\n  rdoc_options: []\n  require_paths:\n  - lib\n  required_ruby_version: !ruby/object:Gem::Requirement\n    requirements:\n    - &1\n      - \">=\"\n      - !ruby/object:Gem::Version\n        version: '0'\n  required_rubygems_version: !ruby/object:Gem::Requirement\n    requirements:\n    - *1\n  requirements: []\n  rubygems_version: 3.3.7\n  signing_key:\n  specification_version: 4\n  summary:\n  test_files: []\n"], ["created_at", "2022-07-17 12:08:19.272191"], ["updated_at", "2022-07-17 12:08:19.272191"]]
  TRANSACTION (0.9ms)  commit transaction
=>
#<User:0x00000001171ea3a8
...
irb(main):004:0>
irb(main):005:0> User.last.values
  User Load (0.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=>
[Gem::Specification.new do |s|
   s.name = "test"
   s.version = nil
   s.installed_by_version = Gem::Version.new("0")
   s.date = Time.utc(2022, 7, 17)
   s.require_paths = ["lib"]
   s.rubygems_version = "3.3.7"
   s.specification_version = 4
   s.summary = nil
   end]

7.0.3.1では保存、読み込みともにエラーになる

 bundle exec rails c
Loading development environment (Rails 7.0.3.1)
irb(main):001:0> User.last.values
   (1.0ms)  SELECT sqlite_version(*)
  User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
.../psych/class_loader.rb:99:in `find': Tried to load unspecified class: Gem::Specification (Psych::DisallowedClass)

irb(main):002:0> gemspec = Gem::Specification.new("test")
=>
Gem::Specification.new do |s|
...

irb(main):003:0> user = User.create!(values: [gemspec])
  TRANSACTION (0.1ms)  begin transaction
  TRANSACTION (0.0ms)  rollback transaction
.../psych/class_loader.rb:99:in `find': Tried to load unspecified class: Gem::Specification (Psych::DisallowedClass)
.../psych/class_loader.rb:99:in `find': Tried to load unspecified class: Gem::Specification (Psych::DisallowedClass)

7.0.3であってもActiveSupport::Deprecation::DeprecatedInstanceVariableProxyのインスタンスを保存しようとするとエラーとなってうまく行かない

.../psych/visitors/emitter.rb:32:in `scalar': wrong argument type ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy (expected String) (TypeError)

シンボルの保存

7.0.3では保存できる

 bundle exec rails c
Loading development environment (Rails 7.0.3)
irb(main):001:0> User.create(values: [{a: 2}])
   (1.8ms)  SELECT sqlite_version(*)
  TRANSACTION (0.0ms)  begin transaction
  User Create (0.5ms)  INSERT INTO "users" ("values", "created_at", "updated_at") VALUES (?, ?, ?)  [["values", "---\n- :a: 2\n"], ["created_at", "2022-07-17 08:03:26.435339"], ["updated_at", "2022-07-17 08:03:26.435339"]]
  TRANSACTION (0.3ms)  commit transaction
=>
#<User:0x00000001138835d8
 id: 5,
 values: [{:a=>2}],
 created_at: Sun, 17 Jul 2022 08:03:26.435339000 UTC +00:00,
 updated_at: Sun, 17 Jul 2022 08:03:26.435339000 UTC +00:00>

7.0.3.1では保存できない

irb(main):002:0> User.create(values: [{a: 2}])
  TRANSACTION (0.1ms)  begin transaction
  TRANSACTION (0.1ms)  rollback transaction
.../psych/class_loader.rb:99:in `find': Tried to load unspecified class: Symbol (Psych::DisallowedClass)
.../psych/class_loader.rb:99:in `find': Tried to load unspecified class: Symbol (Psych::DisallowedClass)

delayed_job

bundle install

rails g delayed_job:active_record
rake db:migrate
class TestJob < ApplicationJob
  queue_as :default

  def perform(*arg)
    puts arg
  end
end

jobの引数はYAMLとして保存され、delayed_jobにより追加されたYAML.load_djでYAMLが読み込まれる https://github.com/collectiveidea/delayed_job/blob/v4.1.10/lib/delayed/psych_ext.rb#L15

irb(main):001:0> TestJob.perform_later({a: 2})
   (0.6ms)  SELECT sqlite_version(*)
  TRANSACTION (0.0ms)  begin transaction
  Delayed::Backend::ActiveRecord::Job Create (0.8ms)  INSERT INTO "delayed_jobs" ("priority", "attempts", "handler", "last_error", "run_at", "locked_at", "failed_at", "locked_by", "queue", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["priority", 0], ["attempts", 0], ["handler", "--- !ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper\njob_data:\n  job_class: TestJob\n  job_id: bb5c0a70-0ee8-4435-8e1c-2fc934f90c38\n  provider_job_id:\n  queue_name: default\n  priority:\n  arguments:\n  - a: 2\n    _aj_symbol_keys:\n    - a\n  executions: 0\n  exception_executions: {}\n  locale: en\n  timezone: UTC\n  enqueued_at: '2022-08-06T05:24:25Z'\n"], ["last_error", nil], ["run_at", "2022-08-06 05:24:25.560338"], ["locked_at", nil], ["failed_at", nil], ["locked_by", nil], ["queue", "default"], ["created_at", "2022-08-06 05:24:25.560377"], ["updated_at", "2022-08-06 05:24:25.560377"]]
  TRANSACTION (0.4ms)  commit transaction

delayed_jobのシリアライズはActiveRecordのものではないため、Railsのバージョンの影響を受けず、クラスが制限されない

 bundle exec rails c
Loading development environment (Rails 7.0.3.1)
irb(main):001:0> TestJob.perform_now("test")
Performing TestJob (Job ID: 350a9420-0609-4b82-b860-d01be744dfaa) from DelayedJob(default) enqueued at  with arguments: "test"
test
Performed TestJob (Job ID: 350a9420-0609-4b82-b860-d01be744dfaa) from DelayedJob(default) in 1.66ms
=> nil

irb(main):002:0> gemspec = Gem::Specification.new("test")

irb(main):003:0> TestJob.perform_now(gemspec)
Performing TestJob (Job ID: 35ca24aa-18e4-4477-a92f-2247621c211e) from DelayedJob(default) enqueued at  with arguments: #<Gem::Specification:...
#<Gem::Specification name=test version=>
Performed TestJob (Job ID: 35ca24aa-18e4-4477-a92f-2247621c211e) from DelayedJob(default) in 0.73ms
=> nil
irb(main):004:0>

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published